using System;
using System.Collections;
using HCore.Unity.Core;
using JetBrains.Annotations;
using Session;
using UnityEngine;

namespace Game.Tile
{
    [UsedImplicitly]
    [HCore.IOC.Context.Stereotype.Component]
    public class TileService : SessionProvider
    {
        /// <summary>
        ///     此功能负责基于不透明的基础纹理生成拼图瓷砖。
        ///     <para>请注意，只能在主线程中调用</para>
        /// </summary>
        /// <param name="addTileVisualFunc"></param>
        /// <param name="getTileVisualFunc"></param>
        /// <returns></returns>
        public IEnumerator CreateTileVisuals(
            Func<Vector2Int, TileVisual, IEnumerator> addTileVisualFunc,
            Func<Vector2Int, TileVisual> getTileVisualFunc)
        {
            if (Session?.Board == null) yield break;
            var board = Session.Board;

            foreach (var tile in board.Tiles)
            {
                // 把 Tile 索引添加进 Board 受控列表
                board.AddControlTile(tile.Index);

                // 构建 TileVisual
                var tileVisual = CreateTileVisual(tile, getTileVisualFunc);
                yield return addTileVisualFunc.Invoke(tile.Index, tileVisual);
            }

            // 排序， 更友好的在Game界面显示
            board.SortControlTiles();
            yield return null;
        }

        /// <summary>
        ///     此功能旨在生成一个 GameObject ，基于提供的 Tile 对象，在拼图中代表瓷砖。
        ///     <para>请注意，只能在主线程中调用</para>
        /// </summary>
        /// <param name="tile"></param>
        /// <param name="getTileVisualFunc"></param>
        /// <returns></returns>
        private TileVisual CreateTileVisual(Tile tile, Func<Vector2Int, TileVisual> getTileVisualFunc)
        {
            if (Session?.Board == null) return null;

            var board = Session.Board;
            var effectiveTextureWidth = board.EffectiveTextureWidth;
            var effectiveTextureHeight = board.EffectiveTextureHeight;
            var padding = board.TilePadding;

            ///// 这里为什么要减半呢， 因为根据 TileIndex 来定位，是从左下角开始的，而 OriginalTexture 定位是中心点定位。所以需要把中心点坐标移动到左下角， 就直接 砍半 + 一个 Padding（有白色边框） 即可。
            var half = new Vector3((effectiveTextureWidth - padding) / 2f - padding, (effectiveTextureHeight - padding) / 2f - padding, 0);
            var originalPos = new Vector3(tile.X * tile.TileSize, tile.Y * tile.TileSize, 0.0f) - half;
            var tileGo = new GameObject
            {
                name = $"Tile({tile.X},{tile.Y})",
                transform =
                {
                    position = originalPos
                }
            };

            // 构建 Sprite，并且调整图层排序
            tileGo.AddComponent<SpriteRenderer>().sprite = GameUtils.CreateSprite(tile.FinalCutTexture, new Rect(0, 0, tile.Padding * 2 + tile.TileSize, tile.Padding * 2 + tile.TileSize));

            // 调整碰撞体积，用来检查鼠标点击事件
            tileGo.AddComponent<BoxCollider2D>().size = new Vector2(tile.TileSize + tile.Padding, tile.TileSize + tile.Padding);

            // 添加 Tile控制器
            var tileController = tileGo.AddComponent<TileVisual>();
            tileController.Setup(getTileVisualFunc, Session, tile, originalPos);
            if (Session.RotateTile) tileController.RandomRotate();
            return tileController;
        }
    }
}